home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 7 / Amiga Format AFCD07 (Dec 1996, Issue 91).iso / serious / shareware / programming / aros / exec / freemem.c < prev    next >
C/C++ Source or Header  |  1996-09-13  |  6KB  |  254 lines

  1. /*
  2.     (C) 1995-96 AROS - The Amiga Replacement OS
  3.     $Id: freemem.c,v 1.10 1996/09/13 17:51:23 digulla Exp $
  4.     $Log: freemem.c,v $
  5.     Revision 1.10  1996/09/13 17:51:23  digulla
  6.     Use IPTR
  7.  
  8.     Revision 1.9  1996/09/11 16:56:16  digulla
  9.     Move PurgeChunk() to aros.lib
  10.  
  11.     Revision 1.8  1996/08/23 17:06:56  digulla
  12.     Began work on ressource tracking
  13.  
  14.     Revision 1.7  1996/08/16 14:05:12  digulla
  15.     Added debug output
  16.  
  17.     Revision 1.6  1996/08/15 14:42:15  digulla
  18.     Added comment
  19.  
  20.     Revision 1.5  1996/08/15 13:19:02  digulla
  21.     First attempt to purge memory after free to make code crash which accesses
  22.     memory after a free but just that happens in RemTask().
  23.  
  24.     Revision 1.4  1996/08/13 13:56:02  digulla
  25.     Replaced __AROS_LA by __AROS_LHA
  26.     Replaced some __AROS_LH*I by __AROS_LH*
  27.     Sorted and added includes
  28.  
  29.     Revision 1.3  1996/08/01 17:41:11  digulla
  30.     Added standard header for all files
  31.  
  32.     Desc:
  33.     Lang:
  34. */
  35. #include <exec/alerts.h>
  36. #include <exec/execbase.h>
  37. #include "machine.h"
  38. #include "memory.h"
  39. #include <aros/rt.h>
  40.  
  41. #include "exec_debug.h"
  42. #ifndef DEBUG_FreeMem
  43. #   define DEBUG_FreeMem 0
  44. #endif
  45. #if DEBUG_FreeMem
  46. #   undef DEBUG
  47. #   define DEBUG 1
  48. #endif
  49. #include <aros/debug.h>
  50.  
  51. #define NASTY_FREEMEM    0    /* Delete contents of free'd memory ? */
  52.  
  53. #if NASTY_FREEMEM
  54. extern void PurgeChunk (ULONG *, ULONG);
  55. #endif
  56.  
  57. /*****************************************************************************
  58.  
  59.     NAME */
  60.     #include <exec/memory.h>
  61.     #include <clib/exec_protos.h>
  62.  
  63.     __AROS_LH2(void, FreeMem,
  64.  
  65. /*  SYNOPSIS */
  66.     __AROS_LHA(APTR,  memoryBlock, A1),
  67.     __AROS_LHA(ULONG, byteSize,    D0),
  68.  
  69. /*  LOCATION */
  70.     struct ExecBase *, SysBase, 35, Exec)
  71.  
  72. /*  FUNCTION
  73.     Give a block of memory back to the system pool.
  74.  
  75.     INPUTS
  76.     memoryBlock - Pointer to the memory to be freed
  77.     byteSize    - Size of the block
  78.  
  79.     RESULT
  80.  
  81.     NOTES
  82.  
  83.     EXAMPLE
  84.  
  85.     BUGS
  86.  
  87.     SEE ALSO
  88.     AllocMem()
  89.  
  90.     INTERNALS
  91.  
  92.     HISTORY
  93.     8-10-95    created by m. fleischer
  94.        16-10-95    increased portability
  95.  
  96. ******************************************************************************/
  97. {
  98.     __AROS_FUNC_INIT
  99.  
  100.     struct MemHeader *mh;
  101.     struct MemChunk *p1, *p2, *p3;
  102.     UBYTE *p4;
  103.  
  104.     D(bug("Call FreeMem (%08lx, %ld)\n", memoryBlock, byteSize));
  105.  
  106.     /* If there is no memory free nothing */
  107.     if(!byteSize)
  108.     ReturnVoid ("FreeMem");
  109.  
  110.     RT_Free (RTT_MEMORY, memoryBlock, byteSize);
  111.  
  112.     /* Align size to the requirements */
  113.     byteSize+=(IPTR)memoryBlock&(MEMCHUNK_TOTAL-1);
  114.     byteSize=(byteSize+MEMCHUNK_TOTAL-1)&~(MEMCHUNK_TOTAL-1);
  115.  
  116.     /* Align the block as well */
  117.     memoryBlock=(APTR)((IPTR)memoryBlock&~(MEMCHUNK_TOTAL-1));
  118.  
  119.     /* Start and end(+1) of the block */
  120.     p3=(struct MemChunk *)memoryBlock;
  121.     p4=(UBYTE *)p3+byteSize;
  122.  
  123.     /* Protect the memory list from access by other tasks. */
  124.     Forbid();
  125.  
  126.     /* Loop over MemHeader structures */
  127.     mh=(struct MemHeader *)SysBase->MemList.lh_Head;
  128.     while(mh->mh_Node.ln_Succ)
  129.     {
  130.     /* Test if the memory belongs to this MemHeader. */
  131.     if(mh->mh_Lower<=memoryBlock&&mh->mh_Upper>memoryBlock)
  132.     {
  133. #if !defined(NO_CONSISTENCY_CHECKS)
  134.         /* Test if it really fits into this MemHeader. */
  135.         if((APTR)p4>mh->mh_Upper)
  136.         /* Something is completely wrong. */
  137.         Alert(AN_MemCorrupt|AT_DeadEnd);
  138. #endif
  139.         /*
  140.         The free memory list is only single linked, i.e. to insert
  141.         elements into the list I need the node as well as it's
  142.         predessor. For the first element I can use freeList->mh_First
  143.         instead of a real predessor.
  144.         */
  145.         p1=(struct MemChunk *)&mh->mh_First;
  146.         p2=p1->mc_Next;
  147.  
  148.         /* No chunk in list? Just insert the current one and return. */
  149.         if(p2==NULL)
  150.         {
  151. #if NASTY_FREEMEM
  152.         PurgeChunk ((ULONG *)p3, byteSize);
  153. #endif
  154.         p3->mc_Bytes=byteSize;
  155.         p3->mc_Next=NULL;
  156.         p1->mc_Next=p3;
  157.         mh->mh_Free+=byteSize;
  158.         Permit ();
  159.         ReturnVoid ("FreeMem");
  160.         }
  161.  
  162.         /* Follow the list to find a place where to insert our memory. */
  163.         do
  164.         {
  165. #if !defined(NO_CONSISTENCY_CHECKS)
  166.         /*
  167.             Do some constistency checks:
  168.             1. All MemChunks must be aligned to
  169.                MEMCHUNK_TOTAL.
  170.             2. The end (+1) of the current MemChunk
  171.                must be lower than the start of the next one.
  172.         */
  173.         if(  ((IPTR)p2|p2->mc_Bytes)&(MEMCHUNK_TOTAL-1)
  174.             ||(  (UBYTE *)p2+p2->mc_Bytes>=(UBYTE *)p2->mc_Next
  175.             &&p2->mc_Next!=NULL))
  176.             Alert(AN_MemCorrupt|AT_DeadEnd);
  177. #endif
  178.         /* Found a block with a higher address? */
  179.         if(p2>=p3)
  180.         {
  181. #if !defined(NO_CONSISTENCY_CHECKS)
  182.             /*
  183.             If the memory to be freed overlaps with the current
  184.             block something must be wrong.
  185.             */
  186.             if(p4>(UBYTE *)p2)
  187.             Alert(AN_FreeTwice|AT_DeadEnd);
  188. #endif
  189.             /* End the loop with p2 non-zero */
  190.             break;
  191.         }
  192.         /* goto next block */
  193.         p1=p2;
  194.         p2=p2->mc_Next;
  195.  
  196.         /* If the loop ends with p2 zero add it at the end. */
  197.         }while(p2!=NULL);
  198.  
  199.         /* If there was a previous block merge with it. */
  200.         if(p1!=(struct MemChunk *)&mh->mh_First)
  201.         {
  202. #if !defined(NO_CONSISTENCY_CHECKS)
  203.         /* Check if they overlap. */
  204.         if((UBYTE *)p1+p1->mc_Bytes>(UBYTE *)p3)
  205.             Alert(AN_FreeTwice|AT_DeadEnd);
  206. #endif
  207.         /* Merge if possible */
  208.         if((UBYTE *)p1+p1->mc_Bytes==(UBYTE *)p3)
  209.             p3=p1;
  210.         else
  211.             /* Not possible to merge */
  212.             p1->mc_Next=p3;
  213.         }else
  214.         /*
  215.             There was no previous block. Just insert the memory at
  216.             the start of the list.
  217.         */
  218.         p1->mc_Next=p3;
  219.  
  220.         /* Try to merge with next block (if there is one ;-) ). */
  221.         if(p4==(UBYTE *)p2&&p2!=NULL)
  222.         {
  223.         /*
  224.             Overlap checking already done. Doing it here after
  225.             the list potentially changed would be a bad idea.
  226.         */
  227.         p4+=p2->mc_Bytes;
  228.         p2=p2->mc_Next;
  229.         }
  230.         /* relink the list and return. */
  231. #if NASTY_FREEMEM
  232.         PurgeChunk ((ULONG *)p3, p4-(UBYTE *)p3);
  233. #endif
  234.         p3->mc_Next=p2;
  235.         p3->mc_Bytes=p4-(UBYTE *)p3;
  236.         mh->mh_Free+=byteSize;
  237.         Permit();
  238.         ReturnVoid ("FreeMem");
  239.     }
  240.     mh=(struct MemHeader *)mh->mh_Node.ln_Succ;
  241.     }
  242.  
  243. #if !defined(NO_CONSISTENCY_CHECKS)
  244.     /* Some memory that didn't fit into any MemHeader? */
  245.     Alert(AN_MemCorrupt|AT_DeadEnd);
  246. #else
  247.     Permit();
  248. #endif
  249.  
  250.     ReturnVoid ("FreeMem");
  251.     __AROS_FUNC_EXIT
  252. } /* FreeMem */
  253.  
  254.